/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.planning.tactical.wizard.spray;

import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;
import nl.cloudfarming.client.model.CropProtectionTask;
import nl.cloudfarming.client.model.ProductionUnit;
import nl.cloudfarming.client.planning.tactical.TacticalPlanningModule;
import nl.cloudfarming.client.util.GeometryUtil;
import org.netbeans.validation.api.builtin.Validators;
import org.netbeans.validation.api.ui.ValidationListener;
import org.netbeans.validation.api.ui.ValidationPanel;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;

/**
 * Panel which displays the CropProtectionTasks
 * @author Merijn Zengers
 */
public class OperationPanel extends JPanel implements KeyListener {

    private final String TITLE = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_visual_panel_crop_protection_edit_properties.title");
    private final String ACREAGE_LABEL_TEXT = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_visual_panel_crop_protection_edit_properties.label.acreage");
    private final String PESTICIDE_COLUMN_LABEL_TEXT = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.crop_protection_list_panel.crop_header_pesticide");
    private final String QUANTITY_COLUMN_LABEL_TEXT = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_visual_panel_crop_protection_edit_properties.columnheader.quantity");
    private final String CONCENTRATION_COLUMN_LABEL_TEXT = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_visual_panel_crop_protection_edit_properties.columnheader.concentration");
    private JPanel operationPanel;
    private JLabel acreageLabel;
    private JLabel acreageValue;
    private JLabel pesticideColumnLabel;
    private JLabel quantityColumnLabel;
    private JLabel concentrationColumnLabel;
    private final List<CropProtectionTask> cropProtectionTasks = new ArrayList<CropProtectionTask>();
    public static final int ACREAGE_LABEL_WIDTH = 150;
    private ValidationPanel validationPanel;
    private JLabel pesticideLabel;
    private InputField quantityTextField;
    private JLabel dosageUnitLabel;
    private InputField concentrationTextField;
    private JLabel concentrationDossageUnit;
    public static final int DOSAGE_UNIT_LABEL_WIDTH = 40;
    public static final int PESTICIDE_LABEL_MINIMUN_WIDTH = 150;
    public static final int QUANTITY_TEXTFIELD_PREFERED_WIDTH = 50;
    public static final int CONCENTRATION_TEXTFIELD_PREFERED_WIDTH = 60;
    public static final int CONCENTRATION_DOSAGE_UNIT_LABEL_WIDTH = 50;
    public static final String QUANTITY_TEXT_FIELD_NAME = "quantity";
    public static final String CONCENTRATION_TEXT_FIELD_NAME = "concentration";
    private static final AppLogger LOG = AppLogFactory.getLogger(OperationPanel.class);

    /** Creates new form OperationPanel */
    public OperationPanel() {
        initComponents();
    }

    /**
     * updates the panel according to the available cropProtectionTasks
     */
    private void updatePanel() {
        operationPanel.removeAll();
        operationPanel.add(acreageLabel);
        operationPanel.add(acreageValue, "wrap");

        operationPanel.add(pesticideColumnLabel);
        operationPanel.add(quantityColumnLabel, "align right");
        operationPanel.add(concentrationColumnLabel, "span 2, align right, wrap");

        for (CropProtectionTask cropProtectionTask : cropProtectionTasks) {
            pesticideLabel = new JLabel(cropProtectionTask.getCropProtection().getName());

            quantityTextField = new InputField(cropProtectionTask);
            String quantity = cropProtectionTask.getQuantity() != null ? cropProtectionTask.getQuantity().toString() : "0";
            quantityTextField.setText(quantity);
            quantityTextField.setName(QUANTITY_TEXT_FIELD_NAME);
            quantityTextField.addKeyListener(this);

            dosageUnitLabel = new JLabel(cropProtectionTask.getCropProtection().getDosageUnit().getName());

            concentrationTextField = new InputField(cropProtectionTask);
            concentrationTextField.setName(CONCENTRATION_TEXT_FIELD_NAME);
            concentrationTextField.addKeyListener(this);
            String concentration = cropProtectionTask.getConcentration() != null ? cropProtectionTask.getConcentration().toString() : "0";
            concentrationTextField.setText(concentration);

            concentrationDossageUnit = new JLabel(cropProtectionTask.getCropProtection().getConcentrationDosageUnit().getName());

            pesticideLabel.setPreferredSize(new Dimension(PESTICIDE_LABEL_MINIMUN_WIDTH, 0));
            quantityTextField.setPreferredSize(new Dimension(QUANTITY_TEXTFIELD_PREFERED_WIDTH, 0));
            dosageUnitLabel.setPreferredSize(new Dimension(DOSAGE_UNIT_LABEL_WIDTH, 0));
            concentrationTextField.setPreferredSize(new Dimension(CONCENTRATION_TEXTFIELD_PREFERED_WIDTH, 0));
            concentrationDossageUnit.setPreferredSize(new Dimension(CONCENTRATION_DOSAGE_UNIT_LABEL_WIDTH, 0));

            operationPanel.add(pesticideLabel);
            operationPanel.add(quantityTextField);
            operationPanel.add(dosageUnitLabel);
            operationPanel.add(concentrationTextField);
            operationPanel.add(concentrationDossageUnit);

            cropProtectionTask.addPropertyChangeListener(quantityTextField);
            cropProtectionTask.addPropertyChangeListener(concentrationTextField);

            validationPanel.getValidationGroup().add(this.quantityTextField, Validators.validNumber(Locale.getDefault()));
            validationPanel.getValidationGroup().add(this.concentrationTextField, Validators.validNumber(Locale.getDefault()));
        }
    }

    @Override
    public String getName() {
        return TITLE;
    }

    /*
     * Add a CropProtectionTask to the panel
     */
    public void addCropProtectionTask(CropProtectionTask cropProtectionTask) {
        cropProtectionTasks.add(cropProtectionTask);
        updatePanel();
    }

    /**
     * remove a cropProtectiontask from the panel
     * @param cropProtectionTask to be removed
     */
    public void removeCropProtectionTask(CropProtectionTask cropProtectionTask) {
        cropProtectionTasks.remove(cropProtectionTask);
        updatePanel();
    }

    /**
     * get all the availabel CropProtectionTasks from the panel
     * @return List <CropProtectiontask> all the displayed cropProtectionTasks
     */
    public List<CropProtectionTask> getCropProtectionTasks() {
        return cropProtectionTasks;
    }

    /** 
     * This method is called from within the constructor to
     * initialize the form.
     */
    private void initComponents() {
        ProductionUnit productionUnit = Utilities.actionsGlobalContext().lookup(ProductionUnit.class);
        assert productionUnit != null;

        operationPanel = new JPanel();
        operationPanel.setLayout(new MigLayout("wrap 5"));
        acreageLabel = new JLabel(ACREAGE_LABEL_TEXT);

        acreageLabel.setPreferredSize(new Dimension(ACREAGE_LABEL_WIDTH, 0));
        
        Double roundedValue = GeometryUtil.getAcreageInHA(productionUnit.getAcreage());
        
        acreageValue = new JLabel(roundedValue.toString());

        pesticideColumnLabel = new JLabel(PESTICIDE_COLUMN_LABEL_TEXT);
        quantityColumnLabel = new JLabel(QUANTITY_COLUMN_LABEL_TEXT);
        concentrationColumnLabel = new JLabel(CONCENTRATION_COLUMN_LABEL_TEXT);

        //Validation
        validationPanel = new ValidationPanel();
        validationPanel.setInnerComponent(operationPanel);
        this.add(validationPanel);
        updatePanel();
    }

    /**
     * invokes the validateAll method on the ValidationGroup
     */
    public void validateAll() {
        validationPanel.getValidationGroup().validateAll();
    }

    /**
     * Adds a validationListener to this panels ValidationGroup
     * @param validationListener 
     */
    public void addValidationListener(ValidationListener validationListener) {
        validationPanel.getValidationGroup().add(validationListener);
    }

    /**
     * not used
     * @param e 
     */
    @Override
    public void keyTyped(KeyEvent e) {
    }

    /*
     * Not used
     */
    @Override
    public void keyPressed(KeyEvent e) {
    }

    /**
     * Fired if a key is relaeased on one of the two input fields
     * @param e 
     */
    @Override
    public void keyReleased(KeyEvent e) {
        validateAll();
        if (Pattern.matches("\\d*", Character.toString(e.getKeyChar()))) {
            if (e.getSource() instanceof InputField) {
                InputField inputField = (InputField) e.getSource();
                try {
                    Double value = Double.parseDouble(inputField.getText());
                    if (inputField.getName().equals(QUANTITY_TEXT_FIELD_NAME)) {
                        inputField.getCropProtectionTask().setQuantity(value);
                    } else if (inputField.getName().equals(CONCENTRATION_TEXT_FIELD_NAME)) {
                        inputField.getCropProtectionTask().setConcentration(value);
                    }
                } catch (NumberFormatException ex) {
                    LOG.error("Could not Convert string to number", ex);
                }
            }
        }
    }

    /**
     * implementation of JTextField. Holds the crpProtectionTask for which this inputField is displayed
     */
    private class InputField extends JTextField implements PropertyChangeListener {

        private CropProtectionTask cropProtectionTask;

        public InputField(CropProtectionTask cropProtectionTask) {
            this.cropProtectionTask = cropProtectionTask;
        }

        public CropProtectionTask getCropProtectionTask() {
            return cropProtectionTask;
        }

        @Override
        public void setText(String text) {
            DecimalFormat format = new DecimalFormat("#.###");
            try {
                super.setText(format.format(Double.parseDouble(text)));
            } catch (NumberFormatException ex) {
                LOG.error("Could not Convert string to number", ex);
            }
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(getName())) {
                this.setText(evt.getNewValue().toString());
            }
        }
    }
}
